package com.example.moblie.poll;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import com.example.moblie.R;
import com.google.android.gms.maps.CameraUpdate;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.GoogleMap.InfoWindowAdapter;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.Circle;
import com.google.android.gms.maps.model.CircleOptions;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;

import android.app.Activity;
import android.app.ActionBar;
import android.app.Dialog;
import android.app.Fragment;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.location.Location;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import android.os.Build;

public class MapView extends Activity {
	private GoogleMap map;
	private LatLng previousMyLatLng;
	private Marker myMarker;
	private Circle myCircle;
	private boolean isFirst = true;
	private int definedRadius = 100;
	private boolean onlyInRadius = true;
	private ArrayList<Poll> pollsForLoc;
	private ArrayList<Marker> markerList;
	private ArrayList<Poll> filteredPolls;
	private ArrayList<Marker> filteredMarkerList;
	private boolean oneForFilter = true;
	private int previousNumOfPolls = -2;
	private SharedPreferences mapSettings;
	private Menu menu;

	@SuppressWarnings("deprecation")
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_map_view);

		mapSettings = getSharedPreferences("map", Context.MODE_WORLD_READABLE
				+ Context.MODE_WORLD_WRITEABLE);
		definedRadius = mapSettings.getInt("definedRadius", definedRadius);
		onlyInRadius = mapSettings.getBoolean("onlyInRadius", onlyInRadius);
		Log.d("Radius:enable", String.valueOf(definedRadius) + ":"
				+ onlyInRadius);

		map = ((MapFragment) getFragmentManager().findFragmentById(R.id.map))
				.getMap();
		map.setMyLocationEnabled(true);

		if (getIntent().hasExtra("Filter")) {
			filteredPolls = getIntent().getParcelableArrayListExtra("Filter");
			filteredMarkerList = new ArrayList<Marker>();
		} else {
			// for test
			ArrayList<Poll> list = getIntent().getParcelableArrayListExtra(
					"pollList");
			LatLng[] latlng = new LatLng[list.size()];
			for (int i = 0; i < list.size(); i++) {
				latlng[i] = new LatLng(list.get(i).getLatitude(), list.get(i)
						.getLongitude());
			}
			adjustMap(latlng);
		}

		pollsForLoc = new ArrayList<Poll>();
		markerList = new ArrayList<Marker>();

		map.setOnMyLocationChangeListener(new GoogleMap.OnMyLocationChangeListener() {

			@Override
			public void onMyLocationChange(Location arg0) {
				// TODO Auto-generated method stub
				if (myMarker != null)
					myMarker.remove();
				if (myCircle != null)
					myCircle.remove();

				LatLng myLatLng = new LatLng(arg0.getLatitude(), arg0
						.getLongitude());
				if (previousMyLatLng != null) {
					if (checkDistanceBetweenLocations(previousMyLatLng,
							myLatLng) >= 5) {
						setMeInMap(myLatLng);
					} else {
						Log.d("My Location",
								"the distance between previous and current not >= 5");
						setMeInMap(previousMyLatLng);
					}
				} else {
					setMeInMap(myLatLng);
				}
				previousMyLatLng = myLatLng;

				if (isFirst) {
					isFirst = false;
					CameraUpdate center;
					CameraUpdate zoom;
					center = CameraUpdateFactory.newLatLng(myLatLng);
					zoom = CameraUpdateFactory.zoomTo(15);
					map.moveCamera(center);
					map.animateCamera(zoom);
				}

				if (filteredPolls != null) {
					if (oneForFilter) {
						addMarkers(filteredPolls);
						oneForFilter = false;
					}

				} else {
					LoadPollLocationsTask lplt = new LoadPollLocationsTask();
					lplt.execute();
				}
			}
		});

		// Custom info windows
		// map.setInfoWindowAdapter(new InfoWindowAdapter(){
		//
		// @Override
		// public View getInfoWindow(Marker arg0) {
		// // TODO Auto-generated method stub
		// return null;
		// }
		//
		// @Override
		// public View getInfoContents(Marker arg0) {
		// // TODO Auto-generated method stub
		// View myContentView =
		// getLayoutInflater().inflate(R.layout.custom_info_windows,null);
		//
		// return myContentView;
		// }
		//
		// }
		// );

		map.setOnInfoWindowClickListener(new GoogleMap.OnInfoWindowClickListener() {

			@Override
			public void onInfoWindowClick(Marker arg0) {
				// TODO Auto-generated method stub

				// go view poll
				Log.d("Test", arg0.getTitle());
			}
		});

	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {

		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.map_view, menu);
		MenuItem mi = menu.findItem(R.id.action_onlyInRadius);
		if (onlyInRadius) {
			mi.setTitle("Show only in radius: On");
		} else {
			mi.setTitle("Show only in radius: Off");
		}
		if(filteredPolls != null){
			menu.add(0, Menu.FIRST+1+1, 100, "Clear Filter");
			this.menu = menu;
		}

		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		// Handle action bar item clicks here. The action bar will
		// automatically handle clicks on the Home/Up button, so long
		// as you specify a parent activity in AndroidManifest.xml.
		int id = item.getItemId();
		// if (id == R.id.action_settings) {
		// return true;
		// }
		if(id == 3){
			removeMarkers(filteredMarkerList);
			filteredMarkerList.clear();
			filteredMarkerList = null;
			filteredPolls = null;
			this.menu.removeItem(id);
			showMarkersWithOption();
		}
		
		if (id == R.id.action_onlyInRadius) {
			onlyInRadius = !onlyInRadius;
			if (onlyInRadius) {
				item.setTitle("Show only in radius: On");
			} else {
				item.setTitle("Show only in radius: Off");
			}
			Editor editor = mapSettings.edit();
			editor.putBoolean("onlyInRadius", onlyInRadius);
			editor.commit();
			showMarkersWithOption();
			
			Toast.makeText(this, "Changed show only in radius",
					Toast.LENGTH_SHORT).show();
		}

		if (id == R.id.action_setRadius) {
			final Dialog dialog = new Dialog(MapView.this, R.style.radiusDialog);
			dialog.setContentView(R.layout.alertdialog_adjust_radius);
			dialog.setTitle("Input your radius");

			// set the custom dialog components - text, image and button
			final EditText etRadius = (EditText) dialog
					.findViewById(R.id.etRadius);
			etRadius.setText(String.valueOf(definedRadius));

			Button btnCancel = (Button) dialog
					.findViewById(R.id.btnCancelRadius);
			Button btnChange = (Button) dialog
					.findViewById(R.id.btnChangeRadius);
			// if button is clicked, close the custom dialog
			btnCancel.setOnClickListener(new OnClickListener() {
				@Override
				public void onClick(View v) {
					dialog.dismiss();
				}
			});

			btnChange.setOnClickListener(new OnClickListener() {
				@Override
				public void onClick(View v) {
					if (etRadius.getText() == null
							|| etRadius.getText().toString().equals("")) {
						Toast.makeText(dialog.getContext(),
								"Please input the radius", Toast.LENGTH_SHORT)
								.show();
					} else {
						boolean allDigits = true;
						String temp = etRadius.getText().toString();
						for (int i = 0; i < temp.length(); i++) {
							if (!Character.isDigit(temp.charAt(i))) {
								allDigits = false;
								break;
							}
						}
						if (allDigits) {
							definedRadius = Integer.parseInt(temp);
							Editor editor = mapSettings.edit();
							editor.putInt("definedRadius", definedRadius);
							editor.commit();
							Toast.makeText(dialog.getContext(),
									"New radius saved", Toast.LENGTH_SHORT)
									.show();
							dialog.dismiss();
						} else {
							Toast.makeText(dialog.getContext(),
									"Radius must be numeric",
									Toast.LENGTH_SHORT).show();
						}

					}
				}
			});
			dialog.show();
		}

		return super.onOptionsItemSelected(item);
	}

	private void adjustMap(LatLng[] latlng) {
		addMarkers(latlng);
	}

	//for test
	private void addMarkers(LatLng[] latlng) {
		CameraUpdate center;
		CameraUpdate zoom;
		center = CameraUpdateFactory.newLatLng(latlng[0]);
		zoom = CameraUpdateFactory.zoomTo(15);

		map.moveCamera(center);
		map.animateCamera(zoom);

		MarkerOptions marker1 = new MarkerOptions().position(latlng[0]);
		MarkerOptions marker2 = new MarkerOptions().position(latlng[1]);
		marker1.title("Dum1 Loc");
		marker2.title("Dum2 Loc");
		marker1.snippet("Poll Dum1");
		marker2.snippet("Poll Dum2");
		map.addMarker(marker1);
		map.addMarker(marker2);
	}

	// for filtered
	private void addMarkers(ArrayList<Poll> polls) {
		if(onlyInRadius){
			for (int i = 0; i < polls.size(); i++) {
				Poll p = polls.get(i);
				LatLng temp = new LatLng(p.getLatitude(), p.getLongitude());
				if (checkDistanceBetweenLocations(map.getMyLocation(), temp) <= definedRadius) {
					MarkerOptions mo = new MarkerOptions().position(new LatLng(p
							.getLatitude(), p.getLongitude()));
					mo.title(p.getTitle());
					mo.snippet(p.getCreatorName());
					Marker m = map.addMarker(mo);
					filteredMarkerList.add(m);
					if(filteredMarkerList.size() == 1){
						m.showInfoWindow();
					}
				}
			}
		}else{
			for (int i = 0; i < polls.size(); i++) {
				Poll p = polls.get(i);
				MarkerOptions mo = new MarkerOptions().position(new LatLng(p
						.getLatitude(), p.getLongitude()));
				mo.title(p.getTitle());
				mo.snippet(p.getCreatorName());
				Marker m = map.addMarker(mo);
				filteredMarkerList.add(m);
				if(filteredMarkerList.size() == 1){
					m.showInfoWindow();
				}
			}
		}
		
	}

	//for general
	private void addMarkers() {
		removeMarkers(markerList);
		markerList.clear();
		if (onlyInRadius) {
			for (int i = 0; i < pollsForLoc.size(); i++) {
				Poll p = pollsForLoc.get(i);
				LatLng temp = new LatLng(p.getLatitude(), p.getLongitude());
				if (checkDistanceBetweenLocations(map.getMyLocation(), temp) <= definedRadius) {
					// polls in the defined radius, default: in 100 meters of my
					// location
					MarkerOptions mo = new MarkerOptions().position(temp)
							.title(p.getTitle())
							.snippet("By: " + p.getCreatorName());
					Marker m = map.addMarker(mo);
					markerList.add(m);
					if(markerList.size() == 1){
						m.showInfoWindow();
					}
				}
			}
		} else {
			for (int i = 0; i < pollsForLoc.size(); i++) {
				Poll p = pollsForLoc.get(i);
				LatLng temp = new LatLng(p.getLatitude(), p.getLongitude());

				MarkerOptions mo = new MarkerOptions().position(temp)
						.title(p.getTitle())
						.snippet("By: " + p.getCreatorName());
				Marker m = map.addMarker(mo);
				markerList.add(m);
				if(markerList.size() == 1){
					m.showInfoWindow();
				}
			}
		}

	}
	
	private void showMarkersWithOption(){
		if (myMarker != null)
			myMarker.remove();
		if (myCircle != null)
			myCircle.remove();
		
		if(onlyInRadius){
			if(filteredMarkerList != null){
				removeMarkers(filteredMarkerList);
				filteredMarkerList.clear();
				for (int i = 0; i < filteredPolls.size(); i++) {
					Poll p = filteredPolls.get(i);
					LatLng temp = new LatLng(p.getLatitude(), p.getLongitude());
					if (checkDistanceBetweenLocations(map.getMyLocation(), temp) <= definedRadius) {
						MarkerOptions mo = new MarkerOptions().position(new LatLng(p
								.getLatitude(), p.getLongitude()));
						mo.title(p.getTitle());
						mo.snippet(p.getCreatorName());
						Marker m = map.addMarker(mo);
						filteredMarkerList.add(m);
						if(filteredMarkerList.size() == 1){
							m.showInfoWindow();
						}
					}
				}
			}else{
				removeMarkers(markerList);
				markerList.clear();
				for (int i = 0; i < pollsForLoc.size(); i++) {
					Poll p = pollsForLoc.get(i);
					LatLng temp = new LatLng(p.getLatitude(), p.getLongitude());
					if (checkDistanceBetweenLocations(map.getMyLocation(), temp) <= definedRadius) {
						// polls in the defined radius, default: in 100 meters of my
						// location
						MarkerOptions mo = new MarkerOptions().position(temp)
								.title(p.getTitle())
								.snippet("By: " + p.getCreatorName());
						Marker m = map.addMarker(mo);
						markerList.add(m);
						if(markerList.size() == 1){
							m.showInfoWindow();
						}
					}
				}
			}
		}else{
			if(filteredMarkerList != null){
				removeMarkers(filteredMarkerList);
				filteredMarkerList.clear();
				for (int i = 0; i < filteredPolls.size(); i++) {
					Poll p = filteredPolls.get(i);
					MarkerOptions mo = new MarkerOptions().position(new LatLng(p
							.getLatitude(), p.getLongitude()));
					mo.title(p.getTitle());
					mo.snippet(p.getCreatorName());
					Marker m = map.addMarker(mo);
					filteredMarkerList.add(m);
					if(filteredMarkerList.size() == 1){
						m.showInfoWindow();
					}
				}
			}else{
				removeMarkers(markerList);
				markerList.clear();
				for (int i = 0; i < pollsForLoc.size(); i++) {
					Poll p = pollsForLoc.get(i);
					LatLng temp = new LatLng(p.getLatitude(), p.getLongitude());

					MarkerOptions mo = new MarkerOptions().position(temp)
							.title(p.getTitle())
							.snippet("By: " + p.getCreatorName());
					Marker m = map.addMarker(mo);
					markerList.add(m);
					if(markerList.size() == 1){
						m.showInfoWindow();
					}
				}
			}
			
		}
		
		setMeInMap(new LatLng(map.getMyLocation().getLatitude(),map.getMyLocation().getLongitude()));
	}
	
	private void removeMarkers(ArrayList<Marker> list){
		for(int i = 0; i < list.size(); i++){
			list.get(i).remove();
		}
	}

	private int checkDistanceBetweenLocations(Location loc1, LatLng ll2) {
		Location loc2 = new Location("ll2");

		loc2.setLatitude(ll2.latitude);
		loc2.setLongitude(ll2.longitude);

		return (int) loc1.distanceTo(loc2);
	}

	private int checkDistanceBetweenLocations(LatLng ll1, LatLng ll2) {
		Location loc1 = new Location("ll1");
		Location loc2 = new Location("ll2");

		loc1.setLatitude(ll1.latitude);
		loc1.setLongitude(ll1.longitude);
		loc2.setLatitude(ll2.latitude);
		loc2.setLongitude(ll2.longitude);

		return (int) loc1.distanceTo(loc2);
	}

	private void setMeInMap(LatLng myLatLng) {
		MarkerOptions myMarkerO = new MarkerOptions()
				.position(myLatLng)
				.icon(BitmapDescriptorFactory
						.defaultMarker(BitmapDescriptorFactory.HUE_AZURE))
				.title("My Location").snippet("I'm here");

		myMarker = map.addMarker(myMarkerO);
		// myMarker.showInfoWindow();

		if(onlyInRadius){
			CircleOptions myCircleO = new CircleOptions().center(myLatLng)
					.radius(definedRadius).strokeWidth(2).strokeColor(Color.GREEN)
					.fillColor(0x5500ff00);
			myCircle = map.addCircle(myCircleO);
		}

	}

	private class LoadPollLocationsTask extends AsyncTask<Object, Void, String> {

		private String getPolls() {
			HttpClient httpclient = new DefaultHttpClient();
			HttpPost httppost = new HttpPost(
					"http://myfyp.no-ip.org/cs4295/get_polls_for_location.php");
			try {
				// Add your data

				// Execute HTTP Post Request
				// HttpResponse response = httpclient.execute(httppost);

				// Execute HTTP Post Request
				ResponseHandler<String> responseHandler = new BasicResponseHandler();
				String responseBody = httpclient.execute(httppost,
						responseHandler);
				Log.d("response", "got Data");
				return responseBody;
			} catch (ClientProtocolException e) {
				// TODO Auto-generated catch block
				return e.getMessage();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				return e.getMessage();
			}
		}

		private int getNumOfPolls() {
			HttpClient httpclient = new DefaultHttpClient();
			HttpPost httppost = new HttpPost(
					"http://myfyp.no-ip.org/cs4295/get_count_of_polls.php");
			try {
				// Execute HTTP Post Request
				ResponseHandler<String> responseHandler = new BasicResponseHandler();
				String responseBody = httpclient.execute(httppost,
						responseHandler);
				Log.d("Num of Polls", responseBody);
				return Integer.parseInt(responseBody);
			} catch (ClientProtocolException e) {
				// TODO Auto-generated catch block
				return -1;
			} catch (IOException e) {
				// TODO Auto-generated catch block
				return -1;
			}
		}

		@Override
		protected String doInBackground(Object... params) {
			// TODO Auto-generated method stub
			int currentNumOfPolls = getNumOfPolls();
			if (previousNumOfPolls == -2) {
				previousNumOfPolls = currentNumOfPolls;
				return getPolls();
			} else {
				if (previousNumOfPolls != currentNumOfPolls) {
					Log.d("P:C", String.valueOf(previousNumOfPolls) + ":"
							+ String.valueOf(currentNumOfPolls));
					return getPolls();
				}

			}
			return "None";

		}

		@Override
		protected void onPostExecute(String result) {
			// parse json
			if (!result.equals("None")) {
				JSONObject json;
				try {
					json = new JSONObject(result);
					JSONArray listArray = json.getJSONArray("list");
					// Log.d("LEN",String.valueOf(listArray.length()));
					pollsForLoc.clear();
					for (int i = 0; i < listArray.length(); i++) {
						JSONObject obj;
						obj = listArray.getJSONObject(i);
						int groupid = -1;
						String img = "null";

						if (obj.isNull("groupid")) {
							groupid = -1;
						} else {
							groupid = obj.getInt("groupid");
						}

						if (obj.isNull("img")) {
							img = "null";
						} else {
							img = obj.getString("img");
						}

						Poll p = new Poll(obj.getInt("id"),
								obj.getInt("userid"),
								obj.getString("username"),
								obj.getString("title"),
								obj.getString("createdate"), groupid,
								obj.getDouble("latitude"),
								obj.getDouble("longitude"), img);
						pollsForLoc.add(p);
					}
					// Log.d("size",String.valueOf(pollsForLoc.size()));

					// add marker method
					addMarkers();
				} catch (JSONException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}

		}
	}
}
